
// 泛型可以用于 函数、接口、类、type
// 如果在使用的时候 无法确定当时的类型，可以采用泛形来定义
const createArr = <T>(times: number, val: T): T[] => {
    const arr = []
    for (let i = 0; i < times; i++) {
        arr.push(val)
    }
    return arr
    // return Array.from({length:times}).fill(val)  as  T[]
}
console.log(createArr(3, 'abc'))
console.log(createArr(3, 123))

// 写辅助函数的函数的时候可以写 多个泛型用于保存值
// 值的交换
// function swap<T,K>(tuple:[T,K]):[K,T]{
//     return [tuple[1],tuple[0]]
// }
// const r = swap(['jw',true])


// IForEach<T> 表示使用接口的时候确定类型
// <T>():void 在使用这个函数的函数传入类型
// interface IForEach {
//     <T>(arr: T[],callback:(val:T)=>void): void
// }


// type ICallback = <T>(val: T) => void  //  错误写法 泛型的使用需要能正常推到，但是内部的callback没有真正的执行，还是认为arr:T[]
// type IForEach = <T>(arr: T[], callback: ICallback) => void
// const forEach: IForEach = (arr, callback) => {
//     for (let i = 0; i < arr.length; i++) {
//         // ts 并没有真正的执行内部的callback(arr[i])
//         callback(arr[i])
//     }
// }
type ICallback<T> = (val: T) => void  // 2
type IForEach = <T>(arr: T[], callback: ICallback<T>) => void
const forEach: IForEach = (arr, callback) => {
    for (let i = 0; i < arr.length; i++) {
        callback(arr[i])
    }
}
// 使用forEach才传递的类型，而不是定义接口的时候 传递类型

// string | number | {}
forEach(['A', 2, 3,{}], function (val) {
    console.log(val)
})



// 接口的返回值可能都是统一的  
// code, data, message
// 泛型的默认值来解决泛型的值默认情况
interface APIResponse<T = any> {
    error: number,
    data: T,
    message?: string
}
interface LoginInfo {
    username: string,
    token: string
}
function login(): APIResponse<LoginInfo> { // 请求方法
    return {
        error: 1,
        data: {
            username: '张三',
            token: 'xxxx'
        },
        message: '成功'
    }
}
let r = login()


//  在平时开发中我门想使用联合类型 
type IUnion<T = boolean> = T | string | number
type t1 = IUnion
type t2 = IUnion<string[] | number[]>

// 泛型是用户传递的类型（用户随便传？） 在使用泛型的时候 都要添加约束 泛型约束

// 我门在使用泛型的时候 不能直接做运算的 （无法保证泛型的结果 t + t = t?）


// 约束当前这个类型T 需要是 string | number 子类型
function getVal<T extends string | number>(val: T): T {
    return val
}
getVal('123')
getVal(123)
// getVal(true) 因为类型不满足string | number

function getLen<T extends { length: number }>(val: T) {
    return val.length
}
getLen('123')
getLen({ length: 123 })
// getLen(123) 约束是某种类型的子类型

// ts只是对类型做校验，对于真正的业务逻辑不关心
function getObjVal<T extends object, K extends keyof T>(target: T, key: K) {
    return target[key]
}
let person = { name: 'jw', age: 30 };
let animal = { name: 'tom', age: 18, address: 'china' };
getObjVal(animal, "address");


// 类中的泛型

class MyList<T extends string | number = number> {
    private arr: T[] = []
    add(val: T) {
        this.arr.push(val)
    }
    getMax(): T {
        let max = this.arr[0];
        for (let i = 1; i < this.arr.length; i++) {
            let cur = this.arr[i];
            cur > max ? (max = cur) : void 0
        }
        return max
    }
}
const list = new MyList<string>
list.add('1')
list.add('100');
list.add('200');

list.getMax(); // 200

// 求一个数组中的最大值
// 泛型可以使用的场景  函数（参数，返回值） 对象（坑位） 类、 泛型的默认值和 约束
export { }
